#ifndef Math_First
#define Math_First
#ifdef __GNUG__
#pragma interface
#endif

#include "Types.h"

//---- Math --------------------------------------------------------------------

class Math {
public:
	static const double
		Pi,
		E;

	// Trigo
	static double Sin(double);
	static double Cos(double);
	static double ASin(double);
	static double ACos(double);
	static double ATan(double);
	static double ATan2(double, double);
	static int Hypot(int x, int y);     // sqrt(px*px + py*py)
	static double Hypot(double x, double y);

	static void Sincos(double a, double *sin, double *cos);
	static double Atan2(int x, int y);
	static double Atan2(double fx, double fy);

	// Misc
	static int NextPrime(int x);        // least prime number greater than x
	static int Sqrt(int x);
	static double Sqrt(double x);
	static double Ceil(double x);
	static double Floor(double x);
	static double Exp(double);
	static double Power(double x, double y);

	// Abs
	static short Abs(short d);
	static int Abs(int d);
	static long Abs(long d);
	static double Abs(double d);

	// Even/Odd
	static int Even(long a);
	static int Odd(long a);

	// Signum
	static short Sign(short a);
	static int Sign(int a);
	static long Sign(long a);
	static double Sign(double a);

	// Min
	static short Min(short a, short b);
	static u_short Min(u_short a, u_short b);
	static int Min(int a, int b);
	static u_int Min(u_int a, u_int b);
	static long Min(long a, long b);
	static u_long Min(u_long a, u_long b);
	static double Min(double a, double b);

	// Max
	static short Max(short a, short b);
	static u_short Max(u_short a, u_short b);
	static int Max(int a, int b);
	static u_int Max(u_int a, u_int b);
	static long Max(long a, long b);
	static u_long Max(u_long a, u_long b);
	static double Max(double a, double b);

	// Range
	static short Range(short lb, short ub, short x);
	static int Range(int lb, int ub, int x);
	static long Range(long lb, long ub, long x);
	static double Range(double lb, double ub, double x);
};

//---- Sign --------------------------------------------------------------------

inline short Math::Sign(short a)
{
	return (a == 0) ? 0 : ( (a > 0) ? 1 : -1 );
}

inline int Math::Sign(int a)
{
	return (a == 0) ? 0 : ( (a > 0) ? 1 : -1 );
}

inline long Math::Sign(long a)
{
	return (a == 0) ? 0 : ( (a > 0) ? 1 : -1 );
}

inline double Math::Sign(double a)
{
	return (a == 0.0) ? 0 : ( (a > 0.0) ? 1 : -1 );
}

//---- even/odd ----------------------------------------------------------------

inline int Math::Even(long a)
{
	return ! (a & 1);
}

inline int Math::Odd(long a)
{
	return (a & 1);
}

//---- Abs ---------------------------------------------------------------------

inline short Math::Abs(short d)
{
	return (d > 0) ? d : -d;
}

inline int Math::Abs(int d)
{
	return (d > 0) ? d : -d;
}

inline long Math::Abs(long d)
{
	return (d > 0) ? d : -d;
}

inline double Math::Abs(double d)
{
	return (d > 0) ? d : -d;
}

//---- Min ---------------------------------------------------------------------

inline short Math::Min(short a, short b)
{
	return a <= b ? a : b;
}

inline u_short Math::Min(u_short a, u_short b)
{
	return a <= b ? a : b;
}

inline int Math::Min(int a, int b)
{
	return a <= b ? a : b;
}

inline u_int Math::Min(u_int a, u_int b)
{
	return a <= b ? a : b;
}

inline long Math::Min(long a, long b)
{
	return a <= b ? a : b;
}

inline u_long Math::Min(u_long a, u_long b)
{
	return a <= b ? a : b;
}

inline double Math::Min(double a, double b)
{
	return a <= b ? a : b;
}

//---- Max ---------------------------------------------------------------------

inline short Math::Max(short a, short b)
{
	return a >= b ? a : b;
}

inline u_short Math::Max(u_short a, u_short b)
{
	return a >= b ? a : b;
}

inline int Math::Max(int a, int b)
{
	return a >= b ? a : b;
}

inline u_int Math::Max(u_int a, u_int b)
{
	return a >= b ? a : b;
}

inline long Math::Max(long a, long b)
{
	return a >= b ? a : b;
}

inline u_long Math::Max(u_long a, u_long b)
{
	return a >= b ? a : b;
}

inline double Math::Max(double a, double b)
{
	return a >= b ? a : b;
}

//---- Range -------------------------------------------------------------------

inline short Math::Range(short lb, short ub, short x)
{
	return x < lb ? lb : (x > ub ? ub : x);
}

inline int Math::Range(int lb, int ub, int x)
{
	return x < lb ? lb : (x > ub ? ub : x);
}

inline long Math::Range(long lb, long ub, long x)
{
	return x < lb ? lb : (x > ub ? ub : x);
}

inline double Math::Range(double lb, double ub, double x)
{
	return x < lb ? lb : (x > ub ? ub : x);
}

#endif

